package dev.ece.suit.loader.models.fbx;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

public class FBXConnection {
	
	public static final String IDC = "C";

	private String type;
	
	private long from;
	
	private long to;
	
	private Object property;
	
	public static FBXConnection[] parseFBXConnections(FBXElement element) {
		FBXElement[] cs = element.findChildren(IDC);
		FBXConnection[] connections = new FBXConnection[cs.length];
		for(int i=0; i<cs.length; i++) {
			connections[i] = new FBXConnection();
			connections[i].type = (String) cs[i].getProperties()[0].getValue();
			connections[i].from = (Long) cs[i].getProperties()[1].getValue();
			connections[i].to = (Long) cs[i].getProperties()[2].getValue();
			if(cs[i].getProperties().length > 3) {
				connections[i].property = cs[i].getProperties()[2].getValue();
			}
		}
		return connections;
	}
	
	public static Map<Long, List<FBXConnection>> toFBXConnectionsMap(FBXConnection[] connections) {
		Map<Long, List<FBXConnection>> result = new ConcurrentHashMap<Long, List<FBXConnection>>();
		List<FBXConnection> value = null;
		for(FBXConnection connection: connections) {
			value = result.get(connection.getFrom());
			if(value == null) {
				value = new ArrayList<FBXConnection>();
				result.put(connection.getFrom(), value);
			}
			value.add(connection);
		}
		return result;
	}

	public static void connectTextureToMaterial(Map<Long, List<FBXConnection>> connections, FBXTexture[] textures, FBXMaterial[] materials) {
		Map<Long, FBXMaterial> map = FBXMaterial.toFBXMaterialMap(materials);
		List<FBXConnection> conns = null;
		FBXMaterial material = null;
		for(FBXTexture texture: textures) {
			conns = connections.get(texture.getId());
			if(conns != null) {
				for(FBXConnection conn: conns) {
					material = map.get(conn.getTo());
					if(material != null) {
						material.setTextureName(texture.getFileName());
					}
				}
			}
		}
	}
	
	public static void connectMaterialToGeometry(Map<Long, List<FBXConnection>> connections, FBXMaterial[] materials, FBXGeometry[] geometries) {
		Map<Long, FBXGeometry> map = FBXGeometry.toFBXGeometryMap(connections, geometries);
		if(materials != null) {
			List<FBXConnection> conns = null;
			FBXGeometry geometry = null;
			for(int i=0; i<materials.length; i++) {
				conns = connections.get(materials[i].getId());
				if(conns != null) {
					for(FBXConnection conn: conns) {
						geometry = map.get(conn.getTo());
						if(geometry != null) {
							if(geometry.getMaterialIndex() < 0) {
								geometry.setMaterialIndex(i);
							}
						}
					}
				}
			}
		}
	}

	public String getType() {
		return type;
	}

	public long getFrom() {
		return from;
	}

	public long getTo() {
		return to;
	}

	public Object getProperty() {
		return property;
	}

	@Override
	public String toString() {
		return new StringBuilder()
				.append("(type=").append(this.type)
				.append(",from=").append(this.from)
				.append(",to=").append(this.to).append(")").toString();
	}

	@Override
	public int hashCode() {
		return new HashCodeBuilder()
				.append(this.type)
				.append(this.from)
				.append(this.to).toHashCode();
	}

	@Override
	public boolean equals(Object obj) {
		if(obj == null) {
			return false;
		}
		if(!(obj instanceof FBXConnection)) {
			return false;
		}
		if(obj == this) {
			return true;
		}
		FBXConnection connection = (FBXConnection) obj;
		return new EqualsBuilder()
				.append(this.type, connection.type)
				.append(this.from, connection.from)
				.append(this.to, connection.to).isEquals();
	}
	
}
